//This class interprets user input and parses data. It utilizes the 
//QRegExp library to implement basic Natural Language Programming (NLP). 
//This class also serves as a consolidation of all language processing
//functions and its functionality can easily be expanded. This class  
//is implemented in components that require language processing, thereby 
//reducing coupling and increasing cohesion. NLP features supported include
//basic date and time recognition. 

//The APIs of this class are given below:
//	1. Task::TaskType determineTask(string parameters);
//  2. string retrieveParam(Task::TaskType taskType, string &parameters);
//	3. void retrieveParamModify(string &parameters, string &component, string &modifyDetails);
//  4. bool parseComplete(string &parameters);
//  5. Date parseDate(string parameters);
//  6. Time parseTime(string parameters);

//Notes:
//1. Utilizes the QDir, found in the Qt core library. This dependency must
//be included in the release version for it to work.
//2. This class was originally the utility class, containing all the functions
//that extracted, split and compared data. Subsequently the class was split 
//into 2 functions to improve the cohesiveness within each class. The Utility
//class now holds all the functions that extract, split and compare data, while
//the parser handles the interpretation and parsing.

//Acknowledgements:
//	1. CS2103 team F12-4C (QRegExp expressions)

#ifndef PARSER_H_
#define PARSER_H_

#include <QRegExp>
#include <QDateTime>
#include <QString>
#include <vector>
#include <ctype.h>
#include <string>
#include <sstream>
#include <algorithm>
#include <stdlib.h>
#include <assert.h>
#include "Task.h"
#include "Utility.h"
#include "Logger.h"

//QRegExp expressions reproduced with slight modifications and permission from CS2103 team F12-4C.
//@author 
#define RX_EMPTY_STRING "(^\\s*$)"
#define RX_ALL_DIGITS "\\s*(\\d{3,4})\\s*"
#define RX_SHORT_MONTH "(?:the)?\\s*(\\d{1,2})(?:st|nd|rd|th)?\\s*(?:of)?\\s*(jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)\\b\\s*"
#define RX_LONG_MONTH "(?:the)?\\s*(\\d{1,2})(?:st|nd|rd|th)?\\s*(?:of)?\\s*(JANUARY|FEBRUARY|MARCH|APRIL|MAY|JUNE|JULY|AUGUST|SEPTEMBER|OCTOBER|NOVEMBER|DECEMBER)\\b\\s*"
#define RX_SHORT_WEEKDAYS "(?:the|this)?\\s*(?:next|coming)?\\s*(sun|mon|tue|tues|wed|thu|thur|thurs|fri|sat)\\b\\s*"
#define RX_LONG_WEEKDAYS "(?:the|this)?\\s*(?:next|coming)?\\s*(sunday|monday|tuesday|wednesday|thursday|friday|saturday)\\s*"
#define RX_TODAY "\\s*(today|tdy|td)\\s*"
#define RX_TOMORROW "\\s*(tomorrow|tmrw|tmr|tomolo|tml|tomo)\\s*"
#define RX_YESTERDAY "\\s*(yesterday|ystd|ytd|yest)\\s*"
#define RX_DAY_AFTER "\\s*(?:day)\\s*(?:after|aft)\\s*(tomorrow|tommorrow|tommorow|tmr)\\s*"
#define RX_NEXT_WEEK "\\s*(next|nxt)\\s*(week|wk)\\s*"
#define RX_TIME_ALL_DIGITS "\\s*(\\d{3,4})\\s*(?:\\*)?\\s*"
#define RX_AP_TIME "\\s*(\\d{1,2})\\s*(?::)?(\\d{2})\\s*(am|pm)\\s*"
#define RX_24_HOUR_TIME "\\s*(\\d{1,2})\\s*(?::)?(\\d{2})\\s*"
#define RX_AP_TIME_2_DIGITS "\\s*(\\d{1,2})\\s*(am|pm)\\s*"

//@author A0094701J
//Definitions of key variables for matching
#define JANUARY 1
#define FEBRUARY 2
#define MARCH 3
#define APRIL 4
#define MAY 5
#define JUNE 6
#define JULY 7
#define AUGUST 8
#define SEPTEMBER 9
#define OCTOBER 10
#define NOVEMBER 11
#define DECEMBER 12

#define LONG_JAN "january"
#define LONG_FEB "february"
#define LONG_MAR "march"
#define LONG_APR "april"
#define LONG_MAY "may"
#define LONG_JUN "june"
#define LONG_JUL "july"
#define LONG_AUG "august"
#define LONG_SEP "september"
#define LONG_OCT "october"
#define LONG_NOV "november"
#define LONG_DEC "december"

#define SHORT_JAN "jan"
#define SHORT_FEB "feb"
#define SHORT_MAR "mar"
#define SHORT_APR "apr"
#define SHORT_MAY "may"
#define SHORT_JUN "jun"
#define SHORT_JUL "jul"
#define SHORT_AUG "aug"
#define SHORT_SEP "sep"
#define SHORT_OCT "oct"
#define SHORT_NOV "nov"
#define SHORT_DEC "dec"

#define MONDAY 1
#define TUESDAY 2
#define WEDNESDAY 3
#define THURSDAY 4
#define FRIDAY 5
#define SATURDAY 6
#define SUNDAY 7

#define LONG_MON "monday"
#define LONG_TUE "tuesday"
#define LONG_WED "wednesday"
#define LONG_THU "thurday"
#define LONG_FRI "friday"
#define LONG_SAT "saturday"
#define LONG_SUN "sunday"

#define SHORT_MON "mon"
#define SHORT_TUE "tue"
#define SHORT_WED "wed"
#define SHORT_THU "thu"
#define SHORT_FRI "fri"
#define SHORT_SAT "sat"
#define SHORT_SUN "sun"

#define AM "am"
#define PM "pm"

//Definitions of special characters
#define DELIMITER "/"
#define COMPLETE_CHAR "*"

using namespace std;

class Parser {
private:
    Utility util;

    //Parser functions that return a date class
    QDate parseDigitsDate(QString allDigits);
    QDate parseLongShortMonthDate(QString digit, QString month);
    QDate parseLongShortWeekday(QString weekday);
    QDate parseToday();
    QDate parseTomorrow();
    QDate parseYesterday();
    QDate parseDayAfter();
    QDate parseNextWeek();

    //Parser functions that return a time class
	QTime parseDigitsTime(QString allDigits);
    QTime parseAPTime(QString hour, QString minute, QString AMOrPM);
    QTime parseAPTime2Digits(QString hour, QString AMOrPM);
    QTime parse24HourTime(QString hour, QString minute);

	//Functions that match weekday and month values
    int retrieveMonth(QString month);
    int retrieveWeekday(QString weekday);

public:
	//Determines task type from a given string
    Task::TaskType determineTask(QString parameters);
	
	//Functions that parse information and return the relevant parameters
    QString retrieveParam(Task::TaskType taskType, QString &parameters);
	void retrieveParamModify(QString &parameters, QString &component, QString &modifyDetails);
    bool parseComplete(QString &parameters);

	//Date and Time Interpreter functions
    QDate parseDate(QString parameters);
    QTime parseTime(QString parameters);

};

#endif
